package com.fzj.example.jdk18;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.DoubleStream;
import java.util.stream.LongStream;
import java.util.stream.Stream;

/**
 * ClassName: StreamDemo
 * date: 2019/11/13 11:00
 * Description: TODO
 *
 * @author fanzj@bonree.com
 * @since JDK 1.8
 */
public class StreamDemo {

    public static void main(String[] args) {
        /*
        那么什么时候要用stream或者parallelStream呢？三点考虑
            1.是否需要并行
            2.任务之间是否是独立的？是否会引起任何竞态条件？
            3.结果是否取决于任务的调用顺序？
        */
        //方式1
        List<String> arrList=new ArrayList<String>();
        Stream<String> stream=arrList.stream();
        Stream<String> parallelStream=arrList.parallelStream();
        //方式2,注意是引用数据类型，流里面做不了强转
        Integer[] inArr= new Integer[]{1,32,2323};
        Stream<Integer> sreamArr=  Arrays.stream(inArr);
        //方式3
        Stream<String> stringStream2=Stream.of("dfa","fdasfa","fdas","fdaf");
        //方式4
        Stream.iterate(0,(x)->x+2).limit(10).filter((x)->x<8).forEach(System.out::println);
        Stream.generate(()->Math.random()*100).limit(100).forEach(System.out::println);


        //stream-demo
        List<ConsumerTv> testList=Arrays.asList(
                new ConsumerTv(1000,"橘子", ConsumerTv.Status.GOOD,4.0,221,10),
                new ConsumerTv(1001,"橘子", ConsumerTv.Status.NORMAL,3.0,223,110),
                new ConsumerTv(1002,"橘子", ConsumerTv.Status.COMMON,2.0,23,10),
                new ConsumerTv(2000,"苹果", ConsumerTv.Status.GOOD,12.0,223,10),
                new ConsumerTv(2001,"苹果", ConsumerTv.Status.NORMAL,10.0,230,100),
                new ConsumerTv(2002,"苹果", ConsumerTv.Status.COMMON,5.0,200,110),
                new ConsumerTv(3000,"橙子", ConsumerTv.Status.GOOD,10.0,30,20),
                new ConsumerTv(3001,"橙子", ConsumerTv.Status.NORMAL,8.0,30,20),
                new ConsumerTv(4002,"橙子", ConsumerTv.Status.COMMON,5.0,213,190),
                new ConsumerTv(4002,"橙子", ConsumerTv.Status.COMMON,5.0,213,190)
        );
        //中间操作
        //任务1,找出水果出售量过100，货物质量是GOOD，并打印总量
        testList.stream().filter((x)->x.getStatus().equals(ConsumerTv.Status.GOOD) && x.getHasSoleNum()>100).forEach((x)->System.out.println(x.getNum()));
        //任务2,找出苹果产品的出售量
        testList.stream().skip(3).limit(3).forEach((x)->System.out.println(x.getName()+"status:"+x.getStatus()+" has sole:"+x.getHasSoleNum()));
        //任务3,去重
        testList.stream().distinct().forEach(System.out::println);
        //任务3,元素映射,打印其中一个属性值
        testList.stream().map((x)->x.getHasSoleNum()).forEach((x)->System.out.println("has sole:"+x));
        //任务4,元素映射，返回DoubleStream
        DoubleStream doubleStream=testList.stream().mapToDouble((x)->x.getPriceValue()).distinct();
        doubleStream.forEach((x)->System.out.println("出售价格:"+x));
        //任务5，价格排序-升序
        testList.stream().sorted((x,y)->{
            if(x.getPriceValue()<y.getPriceValue()){
                return -1;
            }
            return 1;
        }).forEach((x)->System.out.println(x.getPriceValue()));
        //终止操作
        //任务1:找出水果出售量过100，货物质量是GOOD,存在性
        boolean hasA=testList.stream().anyMatch((x)->x.getStatus().equals(ConsumerTv.Status.GOOD) && x.getHasSoleNum()>100);
        System.out.println("有水果出售量过100，货物质量非常好："+hasA);
        //任务2:是不是所有水果出售量都超过了5,存在性
        boolean hasB=testList.stream().allMatch((x)->x.getHasSoleNum()>5);
        System.out.println("是不是所有水果出售量都超过了10："+hasB);
        //任务3:是不是所有水果出售量都没超过了300,存在性
        boolean hasC=testList.stream().noneMatch((x)->x.getHasSoleNum()>300);
        System.out.println("是不是所有水果出售量都超过了100："+hasC);
        //任务4:求水果中出售价格最高的价格，可以用排序+findFirst
        Optional<Double> optionalDouble=testList.stream().map((x)->x.getPriceValue()).max(Double::compare);
        System.out.println("求水果中出售价格最高的价格:"+optionalDouble.get());
        //testList.stream().map((x)->x.getPriceValue()).max((x,y)->{return Double.compare(x,y);});
        //任务5:求水果中出售价格最低的价格,可以用min
        Optional<ConsumerTv> first=testList.stream().sorted(Comparator.comparingDouble(ConsumerTv::getPriceValue)).distinct().findFirst();
        System.out.println("求水果中出售价格最低的价格:"+first.get().getPriceValue());
        //任务6:商品种类
        long count=testList.stream().map(x->x.getName()).distinct().count();
        System.out.println("商品种类"+count);
        //归约
        //任务1,求出售总量,首先x=0(identity是给流的初始化参数x),归约返回Integer
        System.out.println("水果出售总量"+testList.stream().map(ConsumerTv::getHasSoleNum).reduce(0,(x,y)->x+y));
        //任务2,求出售总量,归约返回Optional<Integer>
        System.out.println("水果出售总量"+testList.stream().map(ConsumerTv::getHasSoleNum).reduce((x,y)->x+y));
        //System.out.println("水果出售总量"+testList.stream().map(ConsumerTv::getHasSoleNum).reduce(Integer::sum);
        //收集
        Set<String> fruitsSet=testList.stream().map(ConsumerTv::getName).distinct().collect(Collectors.toSet());
        List<String> fruitsList=testList.stream().map(ConsumerTv::getName).distinct().collect(Collectors.toList());
        List<String> fruitsList2=testList.stream().map(ConsumerTv::getName).distinct().collect(Collectors.toCollection(ArrayList::new));
        Double avgValue=testList.stream().distinct().collect(Collectors.averagingDouble(ConsumerTv::getPriceValue));
        String collect=testList.stream().map(ConsumerTv::getName).distinct().collect(Collectors.joining("-"));
        System.out.println("avgValue"+avgValue);
        System.out.println("collect"+collect);
        Optional<Integer> collect7 = testList.stream().map(ConsumerTv::getNum).collect(Collectors.reducing(Integer::sum));
        //分组
        //串行流
        long millis = System.currentTimeMillis();
        int num=0;
        for (int i = 0; i < 10000000000L; i++) {
            num+=i;
        }
        // 获取任务的结束时间
        long millis2 = System.currentTimeMillis();
        System.out.println(num);
        System.out.println("使用传统方式计算共用时："+(millis2-millis));
        // 获取任务的开始时间
        long millis3 = System.currentTimeMillis();

        long sum = LongStream.rangeClosed(0L, 10000000000L)
                .parallel()
                .sum();
        // 获取任务的结束时间
        long millis4 = System.currentTimeMillis();
        System.out.println(sum);
        System.out.println("使用Java8并行流方式计算共用时："+(millis4-millis3));
    }
}
